// dependencies
Flair.require('Flair/Controller.js');
Flair.require('Flair/Utility.js');

// declare Index Controller
Flair.Dispatcher = function () {
	// keep track of windows
	this.windows = new Array();
	// controllers exist as singletons
	this.controllerInstances = new Array();
	
	/**
	 * Dispatch the request
	 */
	this.dispatch = function (params) {
		var ops = Flair.extend(Flair.Dispatcher.dispatch_options, params);
	
		var controllerClass = this.toControllerName(ops.controller);
		
		Flair.log('Dispatching:', ops.controller, ops.action);
		
		if(this.controllerInstances[controllerClass])
			; // do nothing 
		else if(Flair.Controllers[controllerClass]) {
			this.controllerInstances[controllerClass] = new Flair.Controllers[controllerClass]();
		} else {
			Flair.log(controllerClass + ' not loaded. Requiring now.');
			// we need to require the class first, so do that
			// then set a time out to call dispatch again after
			// script has loaded
			Flair.require( this.toFileName(ops.controller), true );
			var that = this;
			// use a setTimeout callback to dispatch for reals
			setTimeout(function () { 
					that.dispatch.call(that, params); 
			}, 1000);
			return;
		}

		// instantiate controller
		var controller = this.controllerInstances[controllerClass];
		controller.setDispatcher(this);
		// call action, or event named
		controller[ this.toActionName(ops.action) ]();

		Flair.log('controller:',controller);
		// direct view to container
		var view = controller.getView();
		if(!view.doRender)
			return;
		
		var window = Flair.Utility.newWindow(null, 
											{width: ops.width, 
											 height: ops.height, 
											 data: Flair.extend(view.getData(), ops.data), 
											 html: view.getOutput()});
		this.windows.push( window );
		return window;
	};
	
	
	/**
	 * Get the class name for a controller
	 * @param {controller} the specified controller
	 * @return string name
	 */
	this.toControllerName = function (controller) {
		controller = controller.substr(0,1).toUpperCase() + controller.substr(1);
		return controller + "Controller";
	};
	/**
	 * Get the function name for action handlers
	 * @param {controller} the specified controller
	 * @return string name
	 */
	this.toActionName = function (action) {
		return action + "Action";
	};
	/**
	 * Get the function name for event handlers
	 * @param {controller} the specified controller
	 * @return string name
	 */
	this.toEventName = function (event) {
		return event + "Event";
	}
	/**
	 * Get the filename for teh controller
	 * @param controller name
	 * @return (relative) path to file
	 */
	this.toFileName = function (controller) {
		return Flair.Dispatcher.dispatch_options.controllerPath + this.toControllerName(controller) + '.js';
	}
};

// expose dispatch options as default values to allow permanent overrides
Flair.Dispatcher.dispatch_options = { 
	controller: 'index'
	,action: 'index'
	,event: null
	,container: 'window'
	,controllerPath: 'controllers/'
	,viewPath: 'views/'
	,width: 200
	,height: 300
	,data: {}
};